home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue61 / Clinic / Object Browser / ObjectBrowserFormU.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2000-03-29  |  14.1 KB  |  503 lines

  1. unit ObjectBrowserFormU;
  2.  
  3. {$ifdef Ver100} { Delphi 3.0x }
  4.   {$define DelphiLessThan4}
  5.   {$define DelphiLessThan5}
  6. {$endif}
  7. {$ifdef Ver110} { C++ Builder 3.0x }
  8.   {$define DelphiLessThan4}
  9.   {$define DelphiLessThan5}
  10. {$endif}
  11. {$ifdef Ver120} { Delphi 4.0x }
  12.   {$define DelphiLessThan5}
  13. {$endif}
  14.  
  15. interface
  16.  
  17. uses
  18.   TypInfo,
  19.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  20.   StdCtrls, ComCtrls, ExtCtrls, Grids, Menus;
  21.  
  22. type
  23.   TObjectBrowserForm = class(TForm)
  24.     Splitter1: TSplitter;
  25.     Splitter2: TSplitter;
  26.     TvOwnerHierarchy: TTreeView;
  27.     Label1: TLabel;
  28.     BtnUpdate: TButton;
  29.     GrdProp: TStringGrid;
  30.     TCPropType: TTabControl;
  31.     Label2: TLabel;
  32.     TvChildrenHierarchy: TTreeView;
  33.     Splitter3: TSplitter;
  34.     Label3: TLabel;
  35.     LstClassHierarchy: TListBox;
  36.     mnuOwnerHierarchy: TPopupMenu;
  37.     itmShowActions: TMenuItem;
  38.     itmShowMenuItems: TMenuItem;
  39.     itmShowActionLists: TMenuItem;
  40.     itmShowPropSets: TMenuItem;
  41.     itmShowPropFields: TMenuItem;
  42.     edtPropValue: TEdit;
  43.     itmHighlightControl: TMenuItem;
  44.     N1: TMenuItem;
  45.     Bar: TStatusBar;
  46.     procedure FormCreate(Sender: TObject);
  47.     procedure FormShow(Sender: TObject);
  48.     procedure ObjectInspectorResize(Sender: TObject);
  49.     procedure BtnUpdateClick(Sender: TObject);
  50.     procedure TvHierarchyChange(Sender: TObject; Node: TTreeNode);
  51.     procedure TCPropTypeChange(Sender: TObject);
  52.     procedure MenuItemClick(Sender: TObject);
  53.     procedure GrdPropSelectCell(Sender: TObject; ACol, ARow: Integer;
  54.       var CanSelect: Boolean);
  55.     procedure edtPropValueKeyDown(Sender: TObject; var Key: Word;
  56.       Shift: TShiftState);
  57.     procedure edtPropValueKeyPress(Sender: TObject; var Key: Char);
  58.     procedure GrdPropMouseDown(Sender: TObject; Button: TMouseButton;
  59.       Shift: TShiftState; X, Y: Integer);
  60.     procedure GrdPropDblClick(Sender: TObject);
  61.   private
  62.     { Private declarations }
  63.     //Flag to stop recursion when tree views change
  64.     Busy: Boolean;
  65.     //The object being displayed in the Object Inspector
  66.     Obj: TObject;
  67.     procedure ListComponents(Root: TComponent; RootNode: TTreeNode);
  68.     procedure ListChildren(Control: TWinControl; RootNode: TTreeNode);
  69.     procedure ListClasses(Obj: TObject);
  70.   protected
  71.     procedure CreateParams(var Params: TCreateParams); override;
  72.     procedure WMEnable(var Msg: TWMEnable);
  73.       message wm_Enable;
  74.   public
  75.     { Public declarations }
  76.     procedure ShowChildrenHierarchy;
  77.     procedure ShowClassHierarchy;
  78.     procedure ShowProperties;
  79.   end;
  80.  
  81. var
  82.   ObjectBrowserForm: TObjectBrowserForm;
  83.  
  84. implementation
  85.  
  86. uses
  87. {$ifndef DelphiLessThan4}
  88.   ActnList,
  89. {$endif}
  90.   Registry, SetEditorFormU, StringsEditorFormU, PropertyHelper;
  91.  
  92. {$R *.DFM}
  93.  
  94. const
  95.   RegPath = 'Software\Oblong';
  96.   RegSection = 'Object Browser';
  97.  
  98. type
  99.   TStringGridAccess = class(TStringGrid);
  100.  
  101. function InheritsFromText(Obj: TObject; const ClsName: String): Boolean;
  102. var
  103.   SenderClass: TClass;
  104. begin
  105.   SenderClass := Obj.ClassType;
  106.   Result := True;
  107.   while SenderClass <> nil do
  108.     if SenderClass.ClassName = ClsName then
  109.       Exit
  110.     else
  111.       SenderClass := SenderClass.ClassParent;
  112.   Result := False;
  113. end;
  114.  
  115. procedure TObjectBrowserForm.FormCreate(Sender: TObject);
  116. begin
  117. {$ifdef DelphiLessThan4}
  118.   itmShowActionLists.Visible := False;
  119.   itmShowActions.Visible := False;
  120. {$endif}
  121.   with TRegIniFile.Create(RegPath) do
  122.     try
  123.       itmHighlightControl.Checked :=
  124.         ReadBool(RegSection, itmHighlightControl.Name, itmHighlightControl.Checked);
  125.     {$ifndef DelphiLessThan4}
  126.       itmShowActions.Checked :=
  127.         ReadBool(RegSection, itmShowActions.Name, itmShowActions.Checked);
  128.       itmShowActionLists.Checked :=
  129.         ReadBool(RegSection, itmShowActionLists.Name, itmShowActionLists.Checked);
  130.     {$endif}
  131.       itmShowMenuItems.Checked :=
  132.         ReadBool(RegSection, itmShowMenuItems.Name, itmShowMenuItems.Checked);
  133.       itmShowPropFields.Checked :=
  134.         ReadBool(RegSection, itmShowPropFields.Name, itmShowPropFields.Checked);
  135.       itmShowPropSets.Checked :=
  136.         ReadBool(RegSection, itmShowPropSets.Name, itmShowPropSets.Checked);
  137.     finally
  138.       Free
  139.     end;
  140. end;
  141.  
  142. procedure TObjectBrowserForm.FormShow(Sender: TObject);
  143. begin
  144.   BtnUpdate.Click;
  145. end;
  146.  
  147. procedure TObjectBrowserForm.ObjectInspectorResize(Sender: TObject);
  148. begin
  149.   GrdProp.DefaultColWidth := (Sender as TWinControl).Width div 2;
  150.   TStringGridAccess(GrdProp).SelectCell(GrdProp.Col, GrdProp.Row)
  151. end;
  152.  
  153. procedure TObjectBrowserForm.ListComponents(Root: TComponent; RootNode: TTreeNode);
  154. var
  155.   Loop: Integer;
  156. begin
  157.   for Loop := 0 to Root.ComponentCount - 1 do
  158.     if not (((Root.Components[Loop] is TMenuItem) and not itmShowMenuItems.Checked) or
  159.           {$ifndef DelphiLessThan4}
  160.             ((Root.Components[Loop] is TCustomAction) and not itmShowActions.Checked) or
  161.             ((Root.Components[Loop] is TCustomActionList) and not itmShowActionLists.Checked) or
  162.           {$endif}
  163.             ((InheritsFromText(Root.Components[Loop], 'TPropField')) and not itmShowPropFields.Checked) or
  164.             ((InheritsFromText(Root.Components[Loop], 'TPropSet')) and not itmShowPropSets.Checked)) then
  165.       ListComponents(
  166.         Root.Components[Loop],
  167.         TvOwnerHierarchy.Items.AddChildObject(
  168.           RootNode,
  169.           Format('%s (%s)',
  170.             [Root.Components[Loop].Name,
  171.              Root.Components[Loop].ClassName]),
  172.           Root.Components[Loop]))
  173. end;
  174.  
  175. procedure TObjectBrowserForm.BtnUpdateClick(Sender: TObject);
  176. begin
  177.   Busy := True;
  178.   try
  179.     TvChildrenHierarchy.Items.Clear;
  180.     LstClassHierarchy.Items.Clear;
  181.     TvOwnerHierarchy.Items.BeginUpdate;
  182.     try
  183.       TvOwnerHierarchy.Items.Clear;
  184.       ListComponents(
  185.         Application,
  186.         TvOwnerHierarchy.Items.AddObject(
  187.           nil,
  188.           'Application (TApplication)',
  189.           Pointer(Application)));
  190.       TvOwnerHierarchy.TopItem := TvOwnerHierarchy.Items[0];
  191.       TvOwnerHierarchy.Items[0].Expand(False)
  192.     finally
  193.       TvOwnerHierarchy.Items.EndUpdate
  194.     end
  195.   finally
  196.     Busy := False
  197.   end
  198. end;
  199.  
  200. procedure TObjectBrowserForm.TvHierarchyChange(Sender: TObject;
  201.   Node: TTreeNode);
  202. var
  203.   Loop: Integer;
  204.   Rect: TRect;
  205.   Canvas: TCanvas;
  206.   Ctl: TControl;
  207. begin
  208.   if Busy then Exit;
  209.   Busy := True;
  210.   try
  211.     Obj := TObject(Node.Data);
  212.     ShowClassHierarchy;
  213.     //This code causes the other tree view to change, causing
  214.     //possible recursion, hence the Busy flag to stop that
  215.     if Sender = TvOwnerHierarchy then
  216.       ShowChildrenHierarchy;
  217.     ShowProperties;
  218.     edtPropValue.Hide;
  219.     if itmHighlightControl.Checked and (Obj is TControl) then
  220.     begin
  221.       Ctl := Obj as TControl;
  222.       Canvas := TCanvas.Create;
  223.       try
  224.         Rect := Ctl.ClientRect;
  225.         Rect.BottomRight := Point(Rect.Left + Rect.Right, Rect.Top + Rect.Bottom);
  226.         Rect.TopLeft := Ctl.ClientToScreen(Rect.TopLeft);
  227.         Rect.BottomRight := Ctl.ClientToScreen(Rect.BottomRight);
  228.         Canvas.Pen.Mode := pmNot;
  229.         Canvas.Pen.Width := 5;
  230.         Canvas.Handle := GetDC(HWnd_Desktop);
  231.         try
  232.           for Loop := 1 to 8 do
  233.           begin
  234.             Canvas.Polyline([Rect.TopLeft, Point(Rect.Right, Rect.Top),
  235.                              Rect.BottomRight, Point(Rect.Left, Rect.Bottom),
  236.                              Rect.TopLeft]);
  237.             Sleep(50);
  238.           end
  239.         finally
  240.           ReleaseDC(HWnd_Desktop, Canvas.Handle)
  241.         end
  242.       finally
  243.         Canvas.Free
  244.       end
  245.     end;
  246.   finally
  247.     Busy := False
  248.   end
  249. end;
  250.  
  251. procedure TObjectBrowserForm.ListChildren(Control: TWinControl; RootNode: TTreeNode);
  252. var
  253.   Loop: Integer;
  254.   NewNode: TTreeNode;
  255. begin
  256.   for Loop := 0 to Control.ControlCount - 1 do
  257.   begin
  258.     NewNode := TvChildrenHierarchy.Items.AddChildObject(
  259.       RootNode, Format('%s (%s)',
  260.         [Control.Controls[Loop].Name,
  261.          Control.Controls[Loop].ClassName]),
  262.       Control.Controls[Loop]);
  263.     if Control.Controls[Loop] is TWinControl then
  264.       ListChildren(TWinControl(Control.Controls[Loop]), NewNode);
  265.   end
  266. end;
  267.  
  268. procedure TObjectBrowserForm.ShowChildrenHierarchy;
  269. var
  270.   WC: TWinControl;
  271. begin
  272.   TvChildrenHierarchy.Items.BeginUpdate;
  273.   try
  274.     TvChildrenHierarchy.Items.Clear;
  275.     if Obj is TWinControl then
  276.     begin
  277.       WC := TWinControl(Obj);
  278.       ListChildren(
  279.         WC,
  280.         TvChildrenHierarchy.Items.AddObject(
  281.           nil,
  282.           Format('%s (%s)', [WC.Name, WC.ClassName]),
  283.           WC));
  284.       end;
  285.     TvChildrenHierarchy.FullExpand
  286.   finally
  287.     TvChildrenHierarchy.Items.EndUpdate
  288.   end
  289. end;
  290.  
  291. procedure TObjectBrowserForm.ListClasses(Obj: TObject);
  292. var
  293.   CurrentClass: TClass;
  294. begin
  295.   CurrentClass := Obj.ClassType;
  296.   while Assigned(CurrentClass) do
  297.   begin
  298.     LstClassHierarchy.Items.Insert(0, CurrentClass.ClassName);
  299.     CurrentClass := CurrentClass.ClassParent
  300.   end
  301. end;
  302.  
  303. procedure TObjectBrowserForm.ShowClassHierarchy;
  304. begin
  305.   LstClassHierarchy.Items.BeginUpdate;
  306.   try
  307.     LstClassHierarchy.Items.Clear;
  308.     ListClasses(Obj)
  309.   finally
  310.     LstClassHierarchy.Items.EndUpdate
  311.   end
  312. end;
  313.  
  314. procedure TObjectBrowserForm.TCPropTypeChange(Sender: TObject);
  315. begin
  316.   ShowProperties;
  317.   edtPropValue.Hide;
  318. end;
  319.  
  320. procedure TObjectBrowserForm.ShowProperties;
  321. const
  322.   PropTypes: array[0..1] of TTypeKinds = (tkProperties, tkMethods);
  323. var
  324.   Loop: Integer;
  325.   List: TPropList;
  326.   Count: Integer;
  327. begin
  328.   FillChar(List, SizeOf(List), 0);
  329.   Count := GetPropList(
  330.     Obj.ClassInfo, PropTypes[TCPropType.TabIndex], @List);
  331.   //If you set a grid's row count to 0, it sets it to 1
  332.   GrdProp.RowCount := Count;
  333.   if Count = 0 then
  334.   begin
  335.     GrdProp.Cells[0, 0] := '';
  336.     GrdProp.Cells[1, 0] := '';
  337.   end;
  338.   //Loop through properties, getting a text version to display
  339.   for Loop := 0 to Count - 1 do
  340.   begin
  341.     GrdProp.Cells[0, Loop] := List[Loop].Name;
  342.     GrdProp.Cells[1, Loop] := GetPropValue(Obj, List[Loop]);
  343.     GrdProp.Objects[1, Loop] := TObject(List[Loop]);
  344.   end
  345. end;
  346.  
  347. procedure TObjectBrowserForm.MenuItemClick(Sender: TObject);
  348. begin
  349.   with Sender as TMenuItem do
  350.   begin
  351.     Checked := not Checked;
  352.     with TRegIniFile.Create(RegPath) do
  353.       try
  354.         WriteBool(RegSection, Name, Checked)
  355.       finally
  356.         Free
  357.       end;
  358.     end;
  359.   if Sender <> itmHighlightControl then
  360.     BtnUpdate.Click
  361. end;
  362.  
  363. procedure TObjectBrowserForm.GrdPropSelectCell(Sender: TObject; ACol,
  364.   ARow: Integer; var CanSelect: Boolean);
  365. begin
  366.   Bar.SimpleText := '';
  367.   if ACol = 1 then
  368.     with edtPropValue do
  369.     begin
  370.       Parent := GrdProp;
  371.       Text := GrdProp.Cells[ACol, ARow];
  372.       Show;
  373.       BoundsRect := GrdProp.CellRect(ACol, ARow);
  374.       SelectAll;
  375.       SetFocus
  376.     end
  377. end;
  378.  
  379. procedure TObjectBrowserForm.edtPropValueKeyDown(Sender: TObject;
  380.   var Key: Word; Shift: TShiftState);
  381. begin
  382.   if Key in [vk_Return, vk_Up, vk_Down] then
  383.   begin
  384.     Bar.SimpleText := '';
  385.     try
  386.       SetPropValue(Obj,
  387.         PPropInfo(GrdProp.Objects[1, GrdProp.Row]), edtPropValue.Text);
  388.     except
  389.       on E: Exception do
  390.         Bar.SimpleText := E.Message
  391.     end;
  392.     ShowProperties;
  393.     case Key of
  394.       vk_Return:
  395.         edtPropValue.Text := GetPropValue(Obj,
  396.           PPropInfo(GrdProp.Objects[1, GrdProp.Row]));
  397.       vk_Up:
  398.         if GrdProp.Row > 0 then
  399.           GrdProp.Row := GrdProp.Row - 1;
  400.       vk_Down:
  401.         if GrdProp.Row <= GrdProp.RowCount then
  402.           GrdProp.Row := GrdProp.Row + 1;
  403.     end;
  404.     Key := 0
  405.   end;
  406. end;
  407.  
  408. procedure TObjectBrowserForm.edtPropValueKeyPress(Sender: TObject;
  409.   var Key: Char);
  410. begin
  411.   case Key of
  412.     #13: Key := #0;
  413.   end
  414. end;
  415.  
  416. procedure TObjectBrowserForm.GrdPropMouseDown(Sender: TObject;
  417.   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  418. var
  419.   Col, Row: Integer;
  420. const
  421.   GR: TGridRect = (Left: -1; Top: -1; Right: -1; Bottom: -1);
  422. begin
  423.   GrdProp.MouseToCell(X, Y, Col, Row);
  424.   if Col = 0 then
  425.   begin
  426.     GR.Left := 1;
  427.     GR.Top := Row;
  428.     GR.BottomRight := GR.TopLeft;
  429.     GrdProp.Selection := GR;
  430.     TStringGridAccess(GrdProp).SelectCell(1, Row);
  431.   end;
  432. end;
  433.  
  434. procedure TObjectBrowserForm.GrdPropDblClick(Sender: TObject);
  435. var
  436.   PropInfo: PPropInfo;
  437.   PropTypeInfo: PTypeInfo;
  438.   PropTypeData: PTypeData;
  439.   PropClass: TClass;
  440. begin
  441.   PropInfo := PPropInfo(GrdProp.Objects[1, GrdProp.Row]);
  442.   PropTypeInfo := PropInfo.PropType^;
  443.   PropTypeData := GetTypeData(PropTypeInfo);
  444.   case PropTypeInfo.Kind of
  445.     tkInteger:
  446.       if Pos('Color', PropInfo.Name) > 0 then
  447.         with TColorDialog.Create(Application) do
  448.           try
  449.             Color := GetOrdProp(Obj, PropInfo);
  450.             if Execute then
  451.               SetOrdProp(Obj, PropInfo, Color)
  452.           finally
  453.             Free
  454.           end;
  455.     tkSet: DisplayModalAndFree(
  456.              TSetEditorForm.Create(Obj, PropInfo));
  457.     tkClass:
  458.     begin
  459.       PropClass := PropTypeData.ClassType;
  460.       //Check for TStrings
  461.       if PropClass.InheritsFrom(TStrings) then
  462.         DisplayModalAndFree(
  463.           TStringsEditorForm.Create(Obj, PropInfo))
  464.       else
  465.       //Check for TFont
  466.       if PropClass.InheritsFrom(TFont) then
  467.         with TFontDialog.Create(Application) do
  468.           try
  469.             Font := TFont(GetObjectProp(Obj, PropInfo, TFont));
  470.             if Execute then
  471.               SetObjectProp(Obj, PropInfo, Font)
  472.           finally
  473.             Free
  474.           end;
  475.     end
  476.   end;
  477.   //After potentially changing a property (say Color),
  478.   //Re-read properties into Object Inspector...
  479.   ShowProperties;
  480.   //...and update the edit control, if needs be
  481.   TStringGridAccess(GrdProp).SelectCell(1, GrdProp.Row);
  482. end;
  483.  
  484. procedure TObjectBrowserForm.CreateParams(var Params: TCreateParams);
  485. begin
  486.   inherited;
  487.   //Make Object Browser have task bar button of its own
  488.   Params.WndParent := HWnd_Desktop
  489. end;
  490.  
  491. procedure TObjectBrowserForm.WMEnable(var Msg: TWMEnable);
  492. begin
  493.   inherited;
  494.   //When another form is modally displayed,
  495.   //stop this one being disabled
  496.   if not Msg.Enabled then
  497.     EnableWindow(Handle, True)
  498. end;
  499.  
  500. initialization
  501.   RegisterClass(TPanel)
  502. end.
  503.